﻿using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using DonetArxLib.DoubleClickHandler;
using System;

//[assembly: CommandClass(typeof(DoubleClickHandlerApp))]
//[assembly: ExtensionApplication(typeof(DoubleClickHandlerApp))]

namespace DonetArxLib.DoubleClickHandler
{
    public class DoubleClickHandlerApp // : IExtensionApplication
    {
        private static bool _handlerLoaded = false;
        private static string _customCmd = null;
        private static ObjectId _selectedEntId = ObjectId.Null;
        private static CustomCommandMappers _customCommands = null;
        private static bool _runCustomCommand = false;


        #region Interface 
        public void Initialize()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;

            try
            {
                ed.WriteMessage($"\nInitializing {this.GetType().Name} ");
                AddDoubleClickHandler();
                ed.WriteMessage("completed\n");
                ed.WriteMessage("\nMy Double-Click Handler has been turned {0}", _handlerLoaded ? "on" : "off");

                Autodesk.AutoCAD.Internal.Utils.PostCommandPrompt();
            }
            catch (System.Exception ex)
            {
                ed.WriteMessage($"failed: \n{ex}");
            }
        }

        public void Terminate()
        {
            
        }

        #endregion

        [CommandMethod("MyDbClick", CommandFlags.Session)]
        public static void ToggleDoubleClickHandling()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;

            PromptKeywordOptions opt = new PromptKeywordOptions("\nToggle My Double-Click Handler on/off");
            opt.Keywords.Add("ON");
            opt.Keywords.Add("OFF");
            opt.Keywords.Default = _handlerLoaded ? "ON" : "OFF";
            opt.AppendKeywordsToMessage = true;

            PromptResult res = ed.GetKeywords(opt);
            if (res.StringResult.ToUpper() == "ON")
                AddDoubleClickHandler();
            else
                RemoveDoubleClickHandler();

            ed.WriteMessage("\nMy Double-Click Handler has been turned {0}", _handlerLoaded ? "on" : "off");
            Autodesk.AutoCAD.Internal.Utils.PostCommandPrompt();
        }

        private static void AddDoubleClickHandler()
        {
            if (_handlerLoaded) return;

            Application.BeginDoubleClick += Application_BeginDoubleClick;
            Application.DocumentManager.DocumentLockModeChanged += DocumentManager_DocumentLockModeChanged;
            Application.DocumentManager.DocumentLockModeChangeVetoed += DocumentManager_DocumentLockModeChangeVetoed;
            _handlerLoaded = true;

            if (_customCommands == null)
                _customCommands = CustomComandsFactory.CreateDefaultCustomCommandMappers();
        }

        private static void RemoveDoubleClickHandler()
        {
            if (!_handlerLoaded) return;
            
            Application.BeginDoubleClick -= Application_BeginDoubleClick;
            Application.DocumentManager.DocumentLockModeChanged -= DocumentManager_DocumentLockModeChanged;
            Application.DocumentManager.DocumentLockModeChangeVetoed -= DocumentManager_DocumentLockModeChangeVetoed;

            _customCommands = null;
            _handlerLoaded = false;
        }

        private static void DocumentManager_DocumentLockModeChangeVetoed(object sender, DocumentLockModeChangeVetoedEventArgs e)
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            if (doc == null) return;

            Editor ed = doc.Editor;
            if (_runCustomCommand)
            {
                ed.WriteMessage($"\nNow running custom command {_customCmd} against entity {_selectedEntId}");
                LaunchCustomCommand(ed);
            }
        }

        private static void DocumentManager_DocumentLockModeChanged(object sender, DocumentLockModeChangedEventArgs e)
        {
            _runCustomCommand = false;
            Document doc = Application.DocumentManager.MdiActiveDocument;
            if (doc == null) return;

            Editor ed = doc.Editor;

            if (e.GlobalCommandName.Length > 0)
            {
                if (_selectedEntId != ObjectId.Null && !string.IsNullOrEmpty(_customCmd) && e.GlobalCommandName.ToUpper() != _customCmd.ToUpper())
                {
                    ed.WriteMessage($"\nCommand {e.GlobalCommandName} is vetoed!");
                    e.Veto();
                    _runCustomCommand = true;
                }
            }
        }

        private static void Application_BeginDoubleClick(object sender, BeginDoubleClickEventArgs e)
        {
            _customCmd = null;
            _selectedEntId = ObjectId.Null;

            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            PromptSelectionResult res = ed.SelectAtPickBox(e.Location);
            if (res.Status == PromptStatus.OK)
            {
                ObjectId[] ids = res.Value.GetObjectIds();

                if (ids.Length == 1)
                {
                    string cmd = _customCommands.GetCustomCommand(ids[0]);
                    if (!string.IsNullOrEmpty(cmd))
                    {
                        _selectedEntId = ids[0];
                        _customCmd = cmd;

                        ed.WriteMessage($"\nRun command {_customCmd} against entity {_selectedEntId}");

                        if (Convert.ToInt32(Application.GetSystemVariable("DBLCLKEDIT")) == 0)
                        {
                            LaunchCustomCommand(ed);
                        }
                        else
                        {
                            // Since "Double Click Editing" is enabled, a command defined in CUI/CUIX be fired. 
                            // Let the code return and wait the DocumentLockModeChanged and DocumentLockModeChangeVoted
                            // event handler do their job
                            return;
                        }
                    }
                    else
                    {
                        ed.WriteMessage("\nNo custom command is defined against the selected entity");
                    }
                }
                else
                {
                    ed.WriteMessage("\nNo entity or more than one entity was selected!");
                }
            }
            else
            {
                ed.WriteMessage("\n Selections failed!");
            }
        }

        private static void LaunchCustomCommand(Editor ed)
        {
            ed.SetImpliedSelection(new ObjectId[] { _selectedEntId });

            string cmd = _customCmd;
            _customCmd = null;

            Application.DocumentManager.MdiActiveDocument.SendStringToExecute(cmd + " ", true, false, true);
        }
    }
}
